MALHAWK Logo

MalHawk

Reverse Engineering
PLAT:Unix/Linux
DIFF:1.6
QUAL:3.7
2026-06-08

c

You need to guess the password. The password is in a hex string... The difficulty level is closer to 2. Simple program wrote in C and compiled in gcc linux.

This binary uses hex-encoded strings as a light layer of obfuscation. Nothing cryptographic, just raw ASCII values expressed in hex, decoded at runtime.

alt text

The address of the hex string 456e7465722070617373776f72643a20 is loaded into rdi as the first argument. Decoded, that reads Enter password: . An empty buffer's address is prepared and stored in rbx, which is then moved into rsi as the second argument, this buffer is where the decoded output will be written. The decoding function is then called.

Inside the Decoding Function

alt text

The function calls strlen to measure the hex string's length, then immediately shrs (shift right by 1, a fast divide-by-2) that length to calculate how many output bytes it will produce. A hex string is always twice as long as what it represents, "45" is two characters but decodes to one byte ('E'). This gives the loop its stopping point.

The loop itself is straightforward. Every iteration it reads exactly two hex characters, feeds them to strtol with base 16, and writes the resulting single byte into the output buffer. Input pointer advances by 2. Output pointer advances by 1. Loop repeats until all characters are consumed. A null terminator is placed at the end of the output, marking the string as complete.

The decoded Enter password: is printed to the console via printf. fgets then reads the user's input with a maximum of 0x80 (128) bytes, storing it in a stack buffer at rsp.

Because fgets captures the newline character \n from the Enter key press, the program has to strip it before comparison. This is handled by strcspn.

strcspn scans through the input looking for any character that appears in a given reject set, here that set is just "\n". The moment it hits the newline it stops and returns the count of characters before it. If you typed abc and pressed Enter, it returns 3.

That count lands in rax. Then:

mov [rsp + rax], 0
Memory at rsp (after fgets):

Offset:  0    1    2    3    4
Value:  'a'  'b'  'c'  '\n' '\0'
         ↑
        rsp (start of the input buffer)

rax = 3  (strcspn counted 3 characters before hitting '\n')

rsp + rax  =  address of offset 3

mov [rsp + rax], 0  →  writes 0 into offset 3

Result:

Offset:  0    1    2    3    4
Value:  'a'  'b'  'c'  '\0' '\0'
                         ↑
                    '\n' replaced with the string terminator

The hex string 5368616b652069742c206261627921 is loaded into rdi and decoded into a buffer held by rbp. Decoded, that is Shake it, baby!.

strcmp compares the actual byte values of both strings character by character. If every byte matches, it returns 0.

call    _strcmp
test    eax, eax     ; is the result 0?
jnz     loc_117E     ; if NOT zero, jump to the failure path

If the ZF is set, function proceeds to the happy path, that prints the output ok, which is decoded from 6b6f.

Password: Shake it, baby!

alt text

Function Purpose
sub_5555555552A0 (decoding_func) hex-to-ASCII conversion
_strtol (String to Long) Converts a 2-character hex string (e.g. "53") into its numeric byte value (0x53)
_printf Print to the console
_fgets Read user input from stdin (keyboard)
_strcspn (String Complement Span) Locate the reject character - \n position in the input
_strcmp Compare input against the real password
_puts Print final result to the console